package cn.afterturn.easypoi.excel.export;

import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.afterturn.easypoi.excel.export.styler.IExcelExportStyler;
import cn.afterturn.easypoi.exception.excel.ExcelExportException;
import cn.afterturn.easypoi.exception.excel.enums.ExcelExportEnum;
import cn.afterturn.easypoi.util.PoiExcelGraphDataUtil;
import cn.afterturn.easypoi.util.PoiPublicUtil;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 提供批次插入服务
 * @author JueYue
 * 2016年8月29日
 */
public class ExcelBatchExportService extends ExcelExportService {

    private static ThreadLocal<ExcelBatchExportService> THREAD_LOCAL = new ThreadLocal<ExcelBatchExportService>();

    private Workbook workbook;

    private Map<String, SheetParam> sheetParamMap = new HashMap<String, SheetParam>();

    public SheetParam initSheetParam(String sheetName) {
        SheetParam sheetParam = sheetParamMap.get(sheetName);
        if(sheetParam == null) {
            sheetParam = new SheetParam();
            sheetParamMap.put(sheetName, sheetParam);
        }
        return sheetParam;
    }

    public void init(ExportParams entity, Class<?> pojoClass) {
        List<ExcelExportEntity> excelParams = createExcelExportEntityList(entity, pojoClass);
        init(entity, excelParams);
    }

    public void init(ExportParams entity, List<ExcelExportEntity> excelParams) {
        LOGGER.debug("ExcelBatchExportServer only support SXSSFWorkbook");
        entity.setType(ExcelType.XSSF);
        if(workbook == null) {
            workbook = new SXSSFWorkbook();
            super.type = entity.getType();
        }

        Sheet sheet = createSheet(workbook, entity, excelParams);
        if (entity.getMaxNum() == 0) {
            entity.setMaxNum(1000000);
        }

        String sheetName = entity.getSheetName();
        SheetParam sheetParam = initSheetParam(sheetName);
        sheetParam.entity = entity;
        sheetParam.excelParams = excelParams;
        sheetParam.sheet = sheet;

        insertDataToSheet(workbook, sheetParam);
    }

    public List<ExcelExportEntity> createExcelExportEntityList(ExportParams entity, Class<?> pojoClass) {
        try {
            List<ExcelExportEntity> excelParams = new ArrayList<ExcelExportEntity>();
            if (entity.isAddIndex()) {
                excelParams.add(indexExcelEntity(entity));
            }
            // 得到所有字段
            Field[] fileds = PoiPublicUtil.getClassFields(pojoClass);
            ExcelTarget etarget = pojoClass.getAnnotation(ExcelTarget.class);
            String targetId = etarget == null ? null : etarget.value();
            getAllExcelField(entity.getExclusions(), targetId, fileds, excelParams, pojoClass,
                null, null);
            sortAllParams(excelParams);

            return excelParams;
        } catch (Exception e) {
            throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, e);
        }
    }

    public Sheet createSheet(Workbook workbook, ExportParams entity, List<ExcelExportEntity> excelParams) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Excel export start ,List<ExcelExportEntity> is {}", excelParams);
            LOGGER.debug("Excel version is {}",
                entity.getType().equals(ExcelType.HSSF) ? "03" : "07");
        }
        if (workbook == null || entity == null || excelParams == null) {
            throw new ExcelExportException(ExcelExportEnum.PARAMETER_ERROR);
        }
        Sheet sheet;
        try {
            try {
                sheet = workbook.createSheet(entity.getSheetName());
            } catch (Exception e) {
                // 重复遍历,出现了重名现象,创建非指定的名称Sheet
                sheet = workbook.createSheet();
            }
        } catch (Exception e) {
            throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, e);
        }

        return sheet;
    }

    public Workbook appendData(Collection<?> dataSet, String sheetName) {
        SheetParam sheetParam = sheetParamMap.get(sheetName);

        if (sheetParam.sheet.getLastRowNum() + dataSet.size() > sheetParam.entity.getMaxNum()) {
            sheetParam.sheet = workbook.createSheet();
            sheetParam.index = 0;
        }

        Iterator<?> its = dataSet.iterator();
        while (its.hasNext()) {
            Object t = its.next();
            try {
                sheetParam.index += createCells(sheetParam.patriarch, sheetParam.index, t, sheetParam.excelParams, sheetParam.sheet, workbook, sheetParam.rowHeight);
            } catch (Exception e) {
                LOGGER.error(e.getMessage(), e);
                throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, e);
            }
        }
        return workbook;
    }

    protected void insertDataToSheet(Workbook workbook, SheetParam sheetParam) {
        try {
            dataHandler = sheetParam.entity.getDataHandler();
            if (dataHandler != null && dataHandler.getNeedHandlerFields() != null) {
                needHandlerList = Arrays.asList(dataHandler.getNeedHandlerFields());
            }
            // 创建表格样式
            setExcelExportStyler((IExcelExportStyler) sheetParam.entity.getStyle()
                    .getConstructor(Workbook.class).newInstance(workbook));
            sheetParam.patriarch = PoiExcelGraphDataUtil.getDrawingPatriarch(sheetParam.sheet);
            List<ExcelExportEntity> excelParams = new ArrayList<ExcelExportEntity>();
            if (sheetParam.entity.isAddIndex()) {
                excelParams.add(indexExcelEntity(sheetParam.entity));
            }
            excelParams.addAll(sheetParam.excelParams);
            sortAllParams(excelParams);
            sheetParam.index = sheetParam.entity.isCreateHeadRows()
                    ? createHeaderAndTitle(sheetParam.entity, sheetParam.sheet, workbook, excelParams) : 0;
            sheetParam.titleHeight = sheetParam.index;
            setCellWith(excelParams, sheetParam.sheet);
            sheetParam.rowHeight = getRowHeight(excelParams);
            setCurrentIndex(1);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, e.getCause());
        }
    }

    public static ExcelBatchExportService getExcelBatchExportService(ExportParams entity,
                                                                                    Class<?> pojoClass) {
        ExcelBatchExportService batchServer = THREAD_LOCAL.get();
        if (batchServer == null) {
            batchServer = new ExcelBatchExportService();
            batchServer.init(entity, pojoClass);
            THREAD_LOCAL.set(batchServer);
        }

        // 新sheet初始化
        String sheetName = entity.getSheetName();
        SheetParam sheetParam = batchServer.sheetParamMap.get(sheetName);
        if(sheetParam == null) {
            batchServer.init(entity, pojoClass);
        }

        return batchServer;
    }

    public static ExcelBatchExportService getExcelBatchExportService(ExportParams entity,
                                                                                    List<ExcelExportEntity> excelParams) {
        ExcelBatchExportService batchServer = THREAD_LOCAL.get();
        if (batchServer == null) {
            batchServer = new ExcelBatchExportService();
            batchServer.init(entity, excelParams);
            THREAD_LOCAL.set(batchServer);
        }

        // 新sheet初始化
        String sheetName = entity.getSheetName();
        SheetParam sheetParam = batchServer.sheetParamMap.get(sheetName);
        if(sheetParam == null) {
            batchServer.init(entity, excelParams);
        }

        return batchServer;
    }

    public static ExcelBatchExportService getCurrentExcelBatchExportService() {
        return THREAD_LOCAL.get();
    }

    public void closeExportBigExcel() {
        for (Iterator<SheetParam> iterator = sheetParamMap.values().iterator(); iterator.hasNext(); ) {
            SheetParam sheetParam =  iterator.next();
            if (sheetParam.entity.getFreezeCol() != 0) {
                sheetParam.sheet.createFreezePane(sheetParam.entity.getFreezeCol(), 0, sheetParam.entity.getFreezeCol(), 0);
            }
            mergeCells(sheetParam.sheet, sheetParam.excelParams, sheetParam.titleHeight);
            // 创建合计信息
            addStatisticsRow(getExcelExportStyler().getStyles(true, null), sheetParam.sheet);
        }

        THREAD_LOCAL.remove();
    }

    /**
     * sheet相关参数实体类
     *
     * @author zhanls
     * @date 2018-04-08 11:18:56
     */
    private class SheetParam {
        private Sheet sheet;
        private List<ExcelExportEntity> excelParams;
        private ExportParams entity;
        private int titleHeight;
        private Drawing patriarch;
        private short rowHeight;
        private int index;
    }

}
